iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
IT Operation

系統工程師的 30 天自動化維運實戰:PowerShell × AD × Windows Server系列 第 11

Day 11|把 PowerShell Script 拆成 Function:別讓巡檢工具變成 500 行的大檔案

  • 分享至 

  • xImage
  •  

前面 10 天,我們一路把 Windows Server 巡檢功能加進來。

目前已經做到:

Connectivity
CPU
Memory
Disk
Service
Uptime
Event Log
PowerShell Remoting
CSV Report
Error Handling
Log

功能越來越完整,但新的問題也開始出現。

假設我們繼續把所有功能都塞進:

ServerHealthCheck.ps1

最後可能變成:

ServerHealthCheck.ps1

第 1~50 行 Server List
第 51~120 行 Connectivity
第 121~180 行 CPU
第 181~250 行 Memory
第 251~350 行 Disk
第 351~430 行 Service
第 431~520 行 Event Log
第 521~600 行 CSV
第 601~700 行 Error Handling

程式可能還是可以執行。

但過幾個月再回來看,很可能會變成:

「這一段到底是在幹嘛?」

甚至只是想修改 Disk Threshold,卻不敢碰其他地方。

所以 Day 11 先不增加新的巡檢項目。

今天來做另一件對 Automation 很重要的事情:

把 Script 拆成可以重複使用的 Function。

Function 是什麼?

假設我們有一段程式:

$Time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

Add-Content -Path $LogFile
-Value "$Time [INFO] Server Check Started"

每次需要寫 Log,都重新寫一次。

如果一支 Script 有 20 個地方需要 Log,就可能重複 20 次。

比較好的方式是把它包成:

function Write-Log {

param (
    $Message
)

$Time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

Add-Content `
    -Path $LogFile `
    -Value "$Time [INFO] $Message"

}

之後只需要:

Write-Log "Server Check Started"

或:

Write-Log "SERVER01 Check Completed"

Function 可以先簡單理解成:

把一段會重複使用的程式包起來,給它一個名字。

為什麼值得拆 Function?

例如現在 Health Check 有:

CPU Check
Memory Check
Disk Check
Service Check
Uptime Check

如果全部混在一起:

HealthCheck.ps1

400~500 行

當 CPU 計算方式有問題時,我可能要在整份 Script 裡找半天。

如果拆成:

Get-CPUHealth
Get-MemoryHealth
Get-DiskHealth
Get-ServiceHealth
Get-UptimeInfo

問題就變得很明確。

CPU 有問題?

看 Get-CPUHealth

Disk 有問題?

看 Get-DiskHealth

這就是 Function 第一個好處:

縮小問題範圍。

PowerShell Function 基本結構

最簡單:

function Show-Hello {

Write-Host "Hello PowerShell"

}

執行:

Show-Hello

得到:

Hello PowerShell

但真正做維運時,Function 通常需要接收資料。

例如:

function Show-ServerName {

param (
    $ComputerName
)

Write-Host "Checking $ComputerName"

}

執行:

Show-ServerName -ComputerName "SERVER01"

得到:

Checking SERVER01
param 是什麼?

這裡:

param (
$ComputerName
)

代表:

這個 Function 可以接收一個叫做 $ComputerName 的輸入。

例如:

Show-ServerName -ComputerName "SERVER01"

PowerShell 就會:

SERVER01

$ComputerName

所以同一個 Function 可以:

Show-ServerName -ComputerName "SERVER01"
Show-ServerName -ComputerName "SERVER02"
Show-ServerName -ComputerName "SERVER03"

而不用寫三個 Function。

Function 名稱也有習慣

PowerShell Cmdlet 很常看到:

Get-Service
Get-Process
Test-Connection
New-PSSession
Remove-PSSession

也就是:

Verb-Noun

自己寫 Function 時也建議維持這種方式。

例如:

Get-CPUHealth
Get-MemoryHealth
Get-DiskHealth
Test-ServerRemoting
Write-Log

PowerShell 本身也可以查有哪些建議使用的 Verb:

Get-Verb

這不是說 Function 不這樣命名就不能跑。

而是久了之後:

Get → 取得資料
Test → 測試
New → 建立
Remove → 移除
Set → 修改

看到名字,大概就知道 Function 是做什麼的。

第一個實用 Function:Write-Log

我們 Day 6 已經寫過 Log。

現在正式整理一下:

function Write-Log {

param (
    [string]$Message,
    [string]$Level = "INFO"
)

$Time = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

$LogMessage = "$Time [$Level] $Message"

Add-Content `
    -Path $LogFile `
    -Value $LogMessage

}

這次多了一點:

[string]

代表我們預期這個 Parameter 是:

String
文字

另外:

$Level = "INFO"

代表如果沒有指定 Level:

Write-Log "Server Check Started"

預設就是:

INFO

如果:

Write-Log -Message "SERVER01 WinRM Failed"
-Level "ERROR"

才會改成:

2026-09-19 05:10:01 [ERROR] SERVER01 WinRM Failed
第二個 Function:CPU Health

Day 7 的 CPU Check 原本是:

$CPUUsage = [math]::Round(
(
Get-CimInstance Win32_Processor |
Measure-Object -Property LoadPercentage
-Average
).Average,
2
)

接著還有:

if ($CPUUsage -ge 90) {

$CPUStatus = "Critical"

}
elseif ($CPUUsage -ge 80) {

$CPUStatus = "Warning"

}
else {

$CPUStatus = "Normal"

}

現在把它整理成:

function Get-CPUHealth {

$CPUUsage = [math]::Round(
    (
        Get-CimInstance Win32_Processor |
        Measure-Object `
            -Property LoadPercentage `
            -Average
    ).Average,
    2
)


if ($CPUUsage -ge 90) {

    $Status = "Critical"

}
elseif ($CPUUsage -ge 80) {

    $Status = "Warning"

}
else {

    $Status = "Normal"

}


[PSCustomObject]@{

    Usage  = $CPUUsage
    Status = $Status

}

}

執行:

$CPU = Get-CPUHealth

看看:

$CPU

可能得到:

Usage Status


23 Normal
為什麼 Function 回傳 Object?

我們當然可以:

Write-Host "CPU = $CPUUsage"

但這樣後面的程式不好繼續使用資料。

如果回傳:

[PSCustomObject]@{

Usage  = $CPUUsage
Status = $Status

}

那主程式就可以:

$CPU = Get-CPUHealth

接著:

$CPU.Usage

得到:

23

以及:

$CPU.Status

得到:

Normal

未來要輸出 CSV 也很方便。

第三個 Function:Memory Health

接著把 Memory 拆掉。

function Get-MemoryHealth {

$OS = Get-CimInstance Win32_OperatingSystem

$TotalMemory = $OS.TotalVisibleMemorySize
$FreeMemory  = $OS.FreePhysicalMemory

$MemoryUsage = [math]::Round(
    (
        ($TotalMemory - $FreeMemory) /
        $TotalMemory
    ) * 100,
    2
)


if ($MemoryUsage -ge 90) {

    $Status = "Critical"

}
elseif ($MemoryUsage -ge 80) {

    $Status = "Warning"

}
else {

    $Status = "Normal"

}


[PSCustomObject]@{

    Usage = $MemoryUsage

    TotalGB = [math]::Round(
        $TotalMemory / 1024 / 1024,
        2
    )

    FreeGB = [math]::Round(
        $FreeMemory / 1024 / 1024,
        2
    )

    Status = $Status

}

}

執行:

$Memory = Get-MemoryHealth

結果:

Usage TotalGB FreeGB Status


68.31 15.94 5.05 Normal
主程式開始變簡單了

原本 CPU + Memory 可能要寫:

50~100 行

現在主程式只需要:

$CPU = Get-CPUHealth

$Memory = Get-MemoryHealth

後面:

$CPU.Usage

$Memory.Usage

就可以直接使用。

這就是 Function 真正帶來的差別。

第四個 Function:Uptime

Uptime 也很適合拆。

function Get-UptimeInfo {

$OS = Get-CimInstance Win32_OperatingSystem

$LastBootTime = $OS.LastBootUpTime

$Uptime = (Get-Date) - $LastBootTime


if ($Uptime.TotalDays -ge 90) {

    $Status = "Warning"

}
else {

    $Status = "Normal"

}


[PSCustomObject]@{

    LastBootTime = $LastBootTime

    UptimeDays = [math]::Round(
        $Uptime.TotalDays,
        1
    )

    Status = $Status

}

}

執行:

$Uptime = Get-UptimeInfo

可能:

LastBootTime UptimeDays Status


2026/08/15 03:21 35.1 Normal
第五個 Function:Disk Health

Disk 稍微不一樣。

因為:

CPU
→ 一筆結果

Memory
→ 一筆結果

Disk
→ 可能很多筆

例如:

C:
D:
E:

所以 Function 可以直接回傳多個 Object。

function Get-DiskHealth {

$Disks = Get-CimInstance Win32_LogicalDisk `
    -Filter "DriveType=3"


foreach ($Disk in $Disks) {

    if ($Disk.Size -eq 0) {
        continue
    }


    $UsedPercent = [math]::Round(
        (
            ($Disk.Size - $Disk.FreeSpace) /
            $Disk.Size
        ) * 100,
        2
    )


    if ($UsedPercent -ge 90) {

        $Status = "Critical"

    }
    elseif ($UsedPercent -ge 80) {

        $Status = "Warning"

    }
    else {

        $Status = "Normal"

    }


    [PSCustomObject]@{

        Drive = $Disk.DeviceID

        TotalGB = [math]::Round(
            $Disk.Size / 1GB,
            2
        )

        FreeGB = [math]::Round(
            $Disk.FreeSpace / 1GB,
            2
        )

        UsedPercent = $UsedPercent

        Status = $Status

    }

}

}

注意這裡沒有:

$Results +=

而是每次迴圈直接輸出:

[PSCustomObject]

PowerShell 會把這些結果收集起來。

所以:

$Disks = Get-DiskHealth

可能得到:

Drive TotalGB FreeGB UsedPercent Status


C: 237.8 67.3 71.70 Normal
D: 465.6 43.1 90.74 Critical
判斷整體 Disk Status

主程式就可以:

if ($Disks.Status -contains "Critical") {

$DiskStatus = "Critical"

}
elseif ($Disks.Status -contains "Warning") {

$DiskStatus = "Warning"

}
else {

$DiskStatus = "Normal"

}

Function 負責:

怎麼取得 Disk 資料?
怎麼計算 UsedPercent?
怎麼判斷每個 Drive?

主程式只負責:

整體 Disk 是什麼狀態?

責任就開始分得比較清楚。

第六個 Function:Service Health

Day 8 我們定義:

$CriticalServices = @(
"EventLog"
"W32Time"
"Winmgmt"
)

今天可以把 Service List 當成 Function 的 Parameter。

function Get-ServiceHealth {

param (

    [string[]]$ServiceNames

)


foreach ($ServiceName in $ServiceNames) {

    $Service = Get-Service `
        -Name $ServiceName `
        -ErrorAction SilentlyContinue


    if ($null -eq $Service) {

        $Status = "NotFound"

    }
    else {

        $Status = $Service.Status.ToString()

    }


    [PSCustomObject]@{

        ServiceName = $ServiceName

        Status = $Status

    }

}

}

執行:

$CriticalServices = @(
"EventLog"
"W32Time"
"Winmgmt"
)

$Services = Get-ServiceHealth `
-ServiceNames $CriticalServices

結果:

ServiceName Status


EventLog Running
W32Time Running
Winmgmt Running

如果:

W32Time = Stopped

就可以:

$ProblemServices = @(
$Services |
Where-Object {
$_.Status -ne "Running"
}
)

這裡我特別加:

@()

讓結果即使只有一筆,也比較方便使用:

$ProblemServices.Count
Service Function 的價值開始出來了

假設今天是 Domain Controller:

$CriticalServices = @(
"NTDS"
"DNS"
"Netlogon"
"KDC"
"DFSR"
)

Web Server:

$CriticalServices = @(
"W3SVC"
"WAS"
)

SQL:

$CriticalServices = @(
"MSSQLSERVER"
"SQLSERVERAGENT"
)

Function 完全不用改。

只換:

Input

就可以處理不同角色的 Server。

這才是 Function 真正值得做的地方:

邏輯可以重複使用,但輸入可以改變。

Connection 也拆成 Function

Day 10 我們使用:

Test-WSMan

可以整理:

function Test-ServerRemoting {

param (

    [string]$ComputerName

)


try {

    Test-WSMan `
        -ComputerName $ComputerName `
        -ErrorAction Stop |
        Out-Null

    return $true

}
catch {

    return $false

}

}

使用:

if (Test-ServerRemoting -ComputerName "SERVER01") {

Write-Host "WinRM OK"

}
else {

Write-Host "WinRM Failed"

}

主程式已經完全不用知道:

Test-WSMan 怎麼寫
try/catch 怎麼處理

只要知道:

True / False
但這裡有一個 PowerShell Remoting 的重點

假設我們在管理端定義:

function Get-CPUHealth {
...
}

然後:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    Get-CPUHealth

}

不一定可以直接用。

原因是:

在本機定義的 Function,不會自動出現在 Remote PowerShell Session 裡。

本機:

ADMIN-PC

├── Get-CPUHealth
├── Get-MemoryHealth
└── Get-DiskHealth

SERVER01 的 Remote Session 並不知道這些 Function 存在。

那遠端巡檢該怎麼辦?

目前我們可以先採用一個比較好理解的方法:

把遠端需要的 Function 定義放進 Remote ScriptBlock。

例如:

Invoke-Command -ComputerName SERVER01
-ScriptBlock {

    function Get-CPUHealth {

        # CPU Function

    }


    function Get-MemoryHealth {

        # Memory Function

    }


    $CPU = Get-CPUHealth

    $Memory = Get-MemoryHealth

}

這樣 Function 是:

Remote Session 建立

定義 Function

執行 Function

回傳結果

之後再進階,我們可以把 Function:

拆成 .ps1
做成 Module
載入 Module

但 Day 11 先不要一次跳太遠。

建立 Get-ServerHealth

接下來可以再往上包一層。

建立一個:

Get-ServerHealth

專門負責對某台 Server 執行巡檢。

function Get-ServerHealth {

param (

    [Parameter(Mandatory)]
    [string]$ComputerName

)


try {

    Test-WSMan `
        -ComputerName $ComputerName `
        -ErrorAction Stop |
        Out-Null


    $Result = Invoke-Command `
        -ComputerName $ComputerName `
        -ErrorAction Stop `
        -ScriptBlock {


            # =========================
            # CPU
            # =========================

            function Get-CPUHealth {

                $Usage = [math]::Round(
                    (
                        Get-CimInstance Win32_Processor |
                        Measure-Object `
                            -Property LoadPercentage `
                            -Average
                    ).Average,
                    2
                )


                if ($Usage -ge 90) {

                    $Status = "Critical"

                }
                elseif ($Usage -ge 80) {

                    $Status = "Warning"

                }
                else {

                    $Status = "Normal"

                }


                [PSCustomObject]@{

                    Usage = $Usage

                    Status = $Status

                }

            }


            # =========================
            # Memory
            # =========================

            function Get-MemoryHealth {

                $OS = Get-CimInstance Win32_OperatingSystem

                $Usage = [math]::Round(
                    (
                        (
                            $OS.TotalVisibleMemorySize -
                            $OS.FreePhysicalMemory
                        ) /
                        $OS.TotalVisibleMemorySize
                    ) * 100,
                    2
                )


                if ($Usage -ge 90) {

                    $Status = "Critical"

                }
                elseif ($Usage -ge 80) {

                    $Status = "Warning"

                }
                else {

                    $Status = "Normal"

                }


                [PSCustomObject]@{

                    Usage  = $Usage

                    Status = $Status

                }

            }


            # =========================
            # Uptime
            # =========================

            function Get-UptimeInfo {

                $OS = Get-CimInstance Win32_OperatingSystem

                $Uptime =
                    (Get-Date) - $OS.LastBootUpTime


                [PSCustomObject]@{

                    LastBootTime =
                        $OS.LastBootUpTime

                    UptimeDays =
                        [math]::Round(
                            $Uptime.TotalDays,
                            1
                        )

                }

            }


            # =========================
            # Execute Functions
            # =========================

            $CPU = Get-CPUHealth

            $Memory = Get-MemoryHealth

            $Uptime = Get-UptimeInfo


            [PSCustomObject]@{

                ComputerName = $env:COMPUTERNAME

                Connection = "Success"

                CPUUsage = $CPU.Usage

                CPUStatus = $CPU.Status

                MemoryUsage = $Memory.Usage

                MemoryStatus = $Memory.Status

                LastBootTime =
                    $Uptime.LastBootTime

                UptimeDays =
                    $Uptime.UptimeDays

                ErrorMessage = ""

                CheckTime = Get-Date

            }

        }


    return $Result

}
catch {

    return [PSCustomObject]@{

        ComputerName = $ComputerName

        Connection = "Failed"

        CPUUsage = $null

        CPUStatus = "Unknown"

        MemoryUsage = $null

        MemoryStatus = "Unknown"

        LastBootTime = $null

        UptimeDays = $null

        ErrorMessage =
            $_.Exception.Message

        CheckTime = Get-Date

    }

}

}

現在主程式就可以變得非常短。

主程式終於開始像主程式了

以前:

幾百行全部塞在一起

現在:

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

$Results = @()

foreach ($Server in $Servers) {

Write-Host "Checking $Server..."

$Result = Get-ServerHealth `
    -ComputerName $Server

$Results += $Result

}

就這樣。

真正的主流程非常清楚:

讀取 Server List

一台一台處理

Get-ServerHealth

收集 Results

不用再看到:

CPU 計算
Memory 計算
CIM
if
try
catch

全部混在主程式裡。

再建立 Overall Status

拿回資料後可以:

foreach ($Result in $Results) {

if ($Result.Connection -eq "Failed") {

    $OverallStatus = "Unknown"

}
elseif (
    $Result.CPUStatus -eq "Critical" -or
    $Result.MemoryStatus -eq "Critical"
) {

    $OverallStatus = "Critical"

}
elseif (
    $Result.CPUStatus -eq "Warning" -or
    $Result.MemoryStatus -eq "Warning"
) {

    $OverallStatus = "Warning"

}
else {

    $OverallStatus = "Healthy"

}


$Result |
Add-Member `
    -NotePropertyName "OverallStatus" `
    -NotePropertyValue $OverallStatus

}

結果:

Server CPU Memory Connection Overall
SERVER01 21% 62% Success Healthy
SERVER02 85% 71% Success Warning
SERVER03 Failed Unknown

現在:

Connection Failed

不會被誤判成:

Critical

而是:

Unknown

這個邏輯延續 Day 10。

最後輸出 CSV

主程式最後:

$Date = Get-Date -Format "yyyyMMdd"

$ReportFile =
"C:\Temp\Server_Health_$Date.csv"

$Results |
Select-Object ComputerName, Connection, CPUUsage, CPUStatus, MemoryUsage, MemoryStatus, LastBootTime, UptimeDays, OverallStatus, ErrorMessage, CheckTime | Export-Csv
-Path $ReportFile -NoTypeInformation
-Encoding UTF8

主程式現在真正負責的事情變成:

Server List

呼叫巡檢 Function

Overall Status

Export CSV

這樣才比較容易維護。

Function 最好只做一件主要事情

例如:

Get-CPUHealth

最好就是:

取得 CPU Health。

不要最後變成:

Get-CPUHealth

取得 CPU
檢查 Disk
Restart Service
寄 Email
寫 Database
刪 Log

Function 什麼都做的結果,就是重新製造另一個:

巨大 Function。

比較理想的概念是:

Get-CPUHealth
→ CPU

Get-MemoryHealth
→ Memory

Get-DiskHealth
→ Disk

Get-ServiceHealth
→ Service

Write-Log
→ Log

Get-ServerHealth
→ 整合

每一層責任比較清楚。

Threshold 也不應該永遠寫死

目前 Function 裡:

if ($Usage -ge 90)

直接寫死:

90

可以運作。

但未來不同環境可能希望:

CPU Warning = 70
CPU Critical = 90

另一套環境:

CPU Warning = 80
CPU Critical = 95

這時候可以把 Threshold 變成 Parameter。

例如:

function Get-CPUHealth {

param (

    [int]$WarningThreshold = 80,

    [int]$CriticalThreshold = 90

)


$Usage = ...

}

執行:

Get-CPUHealth

使用預設:

80 / 90

也可以:

Get-CPUHealth -WarningThreshold 70
-CriticalThreshold 85

Function 就更容易重複使用。

Parameter 可以設定 Mandatory

剛才 Get-ServerHealth 裡有:

[Parameter(Mandatory)]
[string]$ComputerName

代表:

ComputerName 一定要提供。

如果輸入:

Get-ServerHealth

PowerShell 就會要求:

Supply values for the following parameters:
ComputerName:

因為沒有 ComputerName,這個 Function 根本不知道要巡哪一台。

這比等到程式跑一半才:

ComputerName 是空的

更好。

Function 不是越多越好

這也是值得注意的一點。

不要為了「看起來很專業」:

一行程式

包 Function

另外兩行

再包 Function

Function 真正適合出現的地方通常是:

會重複使用
邏輯可以獨立
值得單獨測試
主程式因此更容易理解

如果 Function 拆得太碎,反而會變成:

Function A

Function B

Function C

Function D

然後想知道一個結果,必須跳來跳去。

所以我們追求的不是:

Function 越多越好。

而是:

每個 Function 有清楚的責任。

怎麼測試 Function?

這也是拆 Function 很大的好處。

以前要測 CPU:

整支 HealthCheck.ps1 全部跑一次

現在只需要:

Get-CPUHealth

Memory:

Get-MemoryHealth

Disk:

Get-DiskHealth

Server:

Get-ServerHealth `
-ComputerName "SERVER01"

如果 Server02 有問題,也只測:

Get-ServerHealth `
-ComputerName "SERVER02"

這就是:

把問題縮小。

對維運工具來說特別重要。

今天整理後的 Script 架構

如果目前還只使用一個 .ps1,可以先長這樣:

ServerHealthCheck.ps1

01 Configuration

├── Server List
├── Threshold
├── Report Path
└── Critical Service

02 Functions

├── Write-Log
├── Test-ServerRemoting
├── Get-CPUHealth
├── Get-MemoryHealth
├── Get-DiskHealth
├── Get-ServiceHealth
├── Get-UptimeInfo
└── Get-ServerHealth

03 Main

├── foreach Server
├── Get-ServerHealth
└── Collect Results

04 Report

├── Overall Status
├── Export-Csv
└── Write-Log

雖然還是一個 .ps1,

但至少已經從:

一大坨程式

變成:

Configuration
Functions
Main
Report

結構清楚很多。

下一階段還可以再拆檔案

未來甚至可以變成:

ServerHealthCheck/

├── Main.ps1

├── Config/
│ └── Servers.csv

├── Functions/
│ ├── Get-CPUHealth.ps1
│ ├── Get-MemoryHealth.ps1
│ ├── Get-DiskHealth.ps1
│ ├── Get-ServiceHealth.ps1
│ ├── Get-UptimeInfo.ps1
│ └── Write-Log.ps1

├── Reports/

└── Logs/

再往前甚至可以做成:

PowerShell Module

例如:

Import-Module SysAdminToolkit

之後直接:

Get-ServerHealth
Get-DiskHealth
Get-ServiceHealth

但這已經是下一階段的事情。

Day 11 先把 Function 的概念弄清楚就好。

Day 11 小結

今天沒有新增任何新的 Windows Server 監控項目。

但我認為今天其實是前 11 天裡很重要的一篇。

因為前面一直在做:

功能
功能
功能
功能

今天第一次停下來思考:

這套 Script 半年後我自己還改得動嗎?

我們開始把:

CPU
Memory
Disk
Service
Uptime
Connection
Log

拆成獨立 Function。

主程式也開始從:

幾百行邏輯

變成:

foreach ($Server in $Servers) {

$Result = Get-ServerHealth `
    -ComputerName $Server

$Results += $Result

}

這才是我希望最後這套工具的樣子。

簡單來說:

以前:

Main Script
├── CPU 細節
├── Memory 細節
├── Disk 細節
├── Service 細節
└── 一堆判斷

現在:

Main Script

├── Get-CPUHealth
├── Get-MemoryHealth
├── Get-DiskHealth
├── Get-ServiceHealth
├── Get-UptimeInfo
└── Write-Log

Function 不只是讓程式比較漂亮。

真正的價值是:

讓每一個問題都有比較清楚的位置可以找。

這其實跟系統維運本身的思維很像。

遇到問題時,不是整台 Server 從頭亂查。

而是:

先分類

縮小範圍

定位問題

處理

寫 Automation Script 也是一樣。

Day 12 預告
Day 12|Server 清單不要寫死:用 CSV 管理不同角色與巡檢設定

現在我們還有一個地方寫死在 Script:

$Servers = @(
"SERVER01"
"SERVER02"
"SERVER03"
)

而且不同 Server 其實不應該使用完全相同的巡檢規則。

例如:

DC01
Role = DomainController
Services = NTDS / DNS / Netlogon / KDC

WEB01
Role = WebServer
Services = W3SVC / WAS

SQL01
Role = Database
Services = MSSQLSERVER / SQLSERVERAGENT

所以 Day 12 我們會開始把:

Server Name
Role
Environment
CPU Threshold
Memory Threshold
Critical Service

從 Script 裡抽出去,建立:

Servers.csv

最後讓程式從:

Import-Csv

自動決定:

這台 Server 是什麼角色,又應該檢查什麼。

到這一步,我們的巡檢工具就會開始從「寫死的 Script」,走向真正比較容易維護的 Configuration-driven Automation。


上一篇
Day 10|從單台走向多台:PowerShell Remoting 批次巡檢 Windows Server
系列文
系統工程師的 30 天自動化維運實戰:PowerShell × AD × Windows Server11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言